Skip to content

Conversation

@codeflash-ai
Copy link
Contributor

@codeflash-ai codeflash-ai bot commented Jun 16, 2025

⚡️ This pull request contains optimizations for PR #309

If you approve this dependent PR, these changes will be merged into the original PR branch updated-vsc-extension.

This PR will be automatically closed if the original PR is merged.


📄 39% (0.39x) speedup for function_kind in codeflash/code_utils/static_analysis.py

⏱️ Runtime : 1.77 milliseconds 1.27 milliseconds (best of 158 runs)

📝 Explanation and details

Here's an optimized version of your program.
Main changes.

  • Replace slices and length-based for-loops with more direct, idiomatic Python control flow (they did nothing).
  • Combine checks for better early returns.
  • Reduce unnecessary list accesses.
  • Process decorator list without unnecessary nesting.
  • No changes to function signatures or output.
    All your in-code comments are preserved (there were none).

Key improvements:

  • Direct mapping of parents[0].type; no useless range-loop.
  • Early exit for empty parents.
  • Avoid redundant list traversal.
  • Set literal for type checking.

This function has the same return signature and logic, but runs faster and is easier to reason about.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 7 Passed
🌀 Generated Regression Tests 2848 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
⚙️ Existing Unit Tests Details
- test_static_analysis.py
🌀 Generated Regression Tests Details
from __future__ import annotations

import ast
from enum import Enum
from typing import List

# imports
import pytest  # used for our unit tests
from codeflash.code_utils.static_analysis import function_kind


# --- Minimal stubs for FunctionKind and FunctionParent for testing ---
class FunctionKind(Enum):
    FUNCTION = "function"
    CLASS_METHOD = "class_method"
    STATIC_METHOD = "static_method"
    INSTANCE_METHOD = "instance_method"

class FunctionParent:
    def __init__(self, type_: str):
        self.type = type_
from codeflash.code_utils.static_analysis import function_kind

# --- Helper functions for tests ---

def make_funcdef(
    name="f",
    decorator_list=None,
    async_=False
):
    """Helper to create ast.FunctionDef or ast.AsyncFunctionDef nodes."""
    if decorator_list is None:
        decorator_list = []
    args = ast.arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[])
    if async_:
        return ast.AsyncFunctionDef(
            name=name, args=args, body=[], decorator_list=decorator_list, returns=None, type_comment=None
        )
    else:
        return ast.FunctionDef(
            name=name, args=args, body=[], decorator_list=decorator_list, returns=None, type_comment=None
        )

# --- Unit tests ---

# 1. Basic Test Cases

def test_top_level_function():
    """Test a top-level (module-level) function."""
    node = make_funcdef()
    parents = []
    codeflash_output = function_kind(node, parents) # 802ns -> 752ns

def test_top_level_async_function():
    """Test a top-level async function."""
    node = make_funcdef(async_=True)
    parents = []
    codeflash_output = function_kind(node, parents) # 741ns -> 711ns

def test_function_inside_function():
    """Test a function defined inside another function."""
    node = make_funcdef()
    parents = [FunctionParent("FunctionDef")]
    codeflash_output = function_kind(node, parents) # 942ns -> 911ns

def test_function_inside_async_function():
    """Test a function defined inside an async function."""
    node = make_funcdef()
    parents = [FunctionParent("AsyncFunctionDef")]
    codeflash_output = function_kind(node, parents) # 912ns -> 842ns

def test_instance_method():
    """Test a method inside a class with no decorators (should be instance method)."""
    node = make_funcdef()
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 2.39μs -> 1.27μs

def test_class_method():
    """Test a method inside a class with @classmethod decorator."""
    node = make_funcdef(decorator_list=[ast.Name(id="classmethod")])
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 2.45μs -> 1.36μs

def test_static_method():
    """Test a method inside a class with @staticmethod decorator."""
    node = make_funcdef(decorator_list=[ast.Name(id="staticmethod")])
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 2.67μs -> 1.27μs

def test_method_with_other_decorator():
    """Test a method inside a class with unrelated decorator (should be instance method)."""
    node = make_funcdef(decorator_list=[ast.Name(id="property")])
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 2.43μs -> 1.44μs

# 2. Edge Test Cases

def test_no_parents_list():
    """Test with parents=None (should treat as top-level function)."""
    node = make_funcdef()
    parents = []
    codeflash_output = function_kind(node, parents) # 731ns -> 651ns

def test_empty_decorator_list():
    """Test with empty decorator list inside class (should be instance method)."""
    node = make_funcdef(decorator_list=[])
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 2.31μs -> 1.23μs

def test_multiple_decorators_classmethod_first():
    """Test method with multiple decorators, classmethod first."""
    node = make_funcdef(decorator_list=[ast.Name(id="classmethod"), ast.Name(id="something_else")])
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 2.46μs -> 1.26μs

def test_multiple_decorators_staticmethod_second():
    """Test method with multiple decorators, staticmethod second."""
    node = make_funcdef(decorator_list=[ast.Name(id="other"), ast.Name(id="staticmethod")])
    parents = [FunctionParent("ClassDef")]
    # Should return STATIC_METHOD as soon as it finds it
    codeflash_output = function_kind(node, parents) # 2.71μs -> 1.44μs

def test_decorator_as_attribute():
    """Test method with decorator as ast.Attribute (should not match)."""
    node = make_funcdef(decorator_list=[ast.Attribute(value=ast.Name(id="abc"), attr="classmethod")])
    parents = [FunctionParent("ClassDef")]
    # Only ast.Name is checked, so should be instance method
    codeflash_output = function_kind(node, parents) # 2.42μs -> 1.28μs

def test_unknown_parent_type():
    """Test with unknown parent type (should return None)."""
    node = make_funcdef()
    parents = [FunctionParent("Module")]
    codeflash_output = function_kind(node, parents) # 1.74μs -> 541ns

def test_nested_class_method():
    """Test method inside class inside function (should still detect as instance method)."""
    node = make_funcdef()
    parents = [FunctionParent("ClassDef"), FunctionParent("FunctionDef")]
    codeflash_output = function_kind(node, parents) # 2.23μs -> 1.18μs

def test_nested_function_in_class():
    """Test function inside function inside class (should be function, not method)."""
    node = make_funcdef()
    parents = [FunctionParent("FunctionDef"), FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 852ns -> 891ns

def test_async_method_in_class():
    """Test async method inside class (should be instance method)."""
    node = make_funcdef(async_=True)
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 2.30μs -> 1.18μs

def test_decorator_name_case_sensitive():
    """Test that decorator name is case sensitive."""
    node = make_funcdef(decorator_list=[ast.Name(id="ClassMethod")])
    parents = [FunctionParent("ClassDef")]
    # 'ClassMethod' is not 'classmethod'
    codeflash_output = function_kind(node, parents) # 2.46μs -> 1.45μs

def test_multiple_classdef_parents():
    """Test with multiple ClassDef parents (should still detect as instance method)."""
    node = make_funcdef()
    parents = [FunctionParent("ClassDef"), FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 2.26μs -> 1.16μs


def test_many_parents_all_functions():
    """Test with a large number of function parents (should still be function)."""
    node = make_funcdef()
    parents = [FunctionParent("FunctionDef") for _ in range(500)]
    codeflash_output = function_kind(node, parents) # 1.18μs -> 1.24μs

def test_many_parents_classdef_first():
    """Test with many parents, first is ClassDef (should be instance method)."""
    node = make_funcdef()
    parents = [FunctionParent("ClassDef")] + [FunctionParent("FunctionDef") for _ in range(999)]
    codeflash_output = function_kind(node, parents) # 17.7μs -> 1.66μs

def test_large_number_of_decorators_staticmethod_last():
    """Test with a large decorator list, staticmethod at the end."""
    decorators = [ast.Name(id=f"decor{i}") for i in range(998)] + [ast.Name(id="staticmethod")]
    node = make_funcdef(decorator_list=decorators)
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 95.7μs -> 82.2μs

def test_large_number_of_decorators_no_match():
    """Test with a large decorator list, none matching."""
    decorators = [ast.Name(id=f"decor{i}") for i in range(1000)]
    node = make_funcdef(decorator_list=decorators)
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 96.5μs -> 83.0μs

def test_large_nested_parents_mixed():
    """Test with 500 ClassDef parents followed by 499 FunctionDef parents."""
    node = make_funcdef()
    parents = [FunctionParent("ClassDef") for _ in range(500)] + [FunctionParent("FunctionDef") for _ in range(499)]
    codeflash_output = function_kind(node, parents) # 17.5μs -> 1.50μs

def test_large_scale_async_staticmethod():
    """Test async static method with large decorator list."""
    decorators = [ast.Name(id=f"decor{i}") for i in range(500)] + [ast.Name(id="staticmethod")]
    node = make_funcdef(decorator_list=decorators, async_=True)
    parents = [FunctionParent("ClassDef")]
    codeflash_output = function_kind(node, parents) # 49.8μs -> 42.7μs
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

from __future__ import annotations

import ast
from dataclasses import dataclass
from enum import Enum

# imports
import pytest  # used for our unit tests
from codeflash.code_utils.static_analysis import function_kind


# Simulate the FunctionKind enum (as not provided)
class FunctionKind(Enum):
    FUNCTION = "function"
    CLASS_METHOD = "class_method"
    STATIC_METHOD = "static_method"
    INSTANCE_METHOD = "instance_method"

# Simulate the FunctionParent dataclass (as not provided)
@dataclass
class FunctionParent:
    type: str  # e.g., "Module", "ClassDef", "FunctionDef", etc.
from codeflash.code_utils.static_analysis import function_kind


# Helper functions for tests
def make_funcdef(name, decorators=None, async_=False):
    """Helper to create ast.FunctionDef or ast.AsyncFunctionDef with given decorators."""
    if decorators is None:
        decorators = []
    if async_:
        return ast.AsyncFunctionDef(
            name=name,
            args=ast.arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]),
            body=[],
            decorator_list=decorators,
            returns=None,
            type_comment=None
        )
    else:
        return ast.FunctionDef(
            name=name,
            args=ast.arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]),
            body=[],
            decorator_list=decorators,
            returns=None,
            type_comment=None
        )

def make_decorator(name):
    """Helper to create ast.Name decorator."""
    return ast.Name(id=name, ctx=ast.Load())

# unit tests

# 1. Basic Test Cases

def test_module_level_function():
    # Function defined at module level (no parents)
    node = make_funcdef("foo")
    parents = []
    codeflash_output = function_kind(node, parents); result = codeflash_output # 752ns -> 691ns

def test_module_level_async_function():
    # Async function at module level
    node = make_funcdef("bar", async_=True)
    parents = []
    codeflash_output = function_kind(node, parents); result = codeflash_output # 732ns -> 661ns

def test_nested_function():
    # Function defined inside another function
    node = make_funcdef("inner")
    parents = [FunctionParent(type="FunctionDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 851ns -> 901ns

def test_class_instance_method():
    # Function defined in class, no decorators
    node = make_funcdef("method")
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.30μs -> 1.09μs

def test_class_classmethod():
    # Function defined in class, with @classmethod decorator
    node = make_funcdef("cmethod", decorators=[make_decorator("classmethod")])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.45μs -> 1.32μs

def test_class_staticmethod():
    # Function defined in class, with @staticmethod decorator
    node = make_funcdef("smethod", decorators=[make_decorator("staticmethod")])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.50μs -> 1.20μs

def test_class_multiple_decorators_staticmethod():
    # Function with multiple decorators, staticmethod is one of them
    node = make_funcdef("smethod", decorators=[make_decorator("foo"), make_decorator("staticmethod")])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.65μs -> 1.37μs

def test_class_multiple_decorators_classmethod():
    # Function with multiple decorators, classmethod is one of them
    node = make_funcdef("cmethod", decorators=[make_decorator("foo"), make_decorator("classmethod")])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.47μs -> 1.43μs

def test_class_decorator_order():
    # Function with both classmethod and staticmethod, classmethod first
    node = make_funcdef("cmethod", decorators=[make_decorator("classmethod"), make_decorator("staticmethod")])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.33μs -> 1.25μs

def test_class_decorator_order_static_first():
    # Function with both staticmethod and classmethod, staticmethod first
    node = make_funcdef("cmethod", decorators=[make_decorator("staticmethod"), make_decorator("classmethod")])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.50μs -> 1.27μs

def test_class_other_decorators():
    # Function with unrelated decorator
    node = make_funcdef("other", decorators=[make_decorator("property")])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.26μs -> 1.27μs

# 2. Edge Test Cases

def test_no_parents_empty_list():
    # No parents (empty list)
    node = make_funcdef("foo")
    parents = []
    codeflash_output = function_kind(node, parents); result = codeflash_output # 661ns -> 671ns

def test_parents_none():
    # Parents is None (should behave as no parents)
    node = make_funcdef("foo")
    parents = None
    # Should not raise, should treat as no parents
    codeflash_output = function_kind(node, parents or []); result = codeflash_output # 692ns -> 621ns

def test_parent_not_module_or_class():
    # Parent is something else (e.g., "Module")
    node = make_funcdef("foo")
    parents = [FunctionParent(type="Module")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 1.75μs -> 501ns

def test_unknown_decorator_type():
    # Decorator is not ast.Name (e.g., ast.Attribute)
    decorator = ast.Attribute(value=ast.Name(id="abc", ctx=ast.Load()), attr="classmethod", ctx=ast.Load())
    node = make_funcdef("foo", decorators=[decorator])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.37μs -> 1.25μs

def test_async_function_in_class():
    # Async function in class, no decorators
    node = make_funcdef("amethod", async_=True)
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.07μs -> 991ns

def test_function_with_unusual_parent_types():
    # Parent is some unknown type
    node = make_funcdef("foo")
    parents = [FunctionParent(type="UnknownType")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 1.69μs -> 531ns

def test_function_with_multiple_parents():
    # Multiple parents, outermost is ClassDef
    node = make_funcdef("foo")
    parents = [FunctionParent(type="ClassDef"), FunctionParent(type="Module")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.21μs -> 1.03μs

def test_function_with_multiple_nested_function_parents():
    # Multiple parents, innermost is FunctionDef, outer is ClassDef
    node = make_funcdef("foo")
    parents = [FunctionParent(type="FunctionDef"), FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 811ns -> 831ns

def test_function_with_asyncfunctiondef_parent():
    # Parent is AsyncFunctionDef
    node = make_funcdef("foo")
    parents = [FunctionParent(type="AsyncFunctionDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 882ns -> 802ns

def test_function_with_decorator_case_sensitivity():
    # Decorator is 'ClassMethod' (wrong case)
    node = make_funcdef("foo", decorators=[make_decorator("ClassMethod")])
    parents = [FunctionParent(type="ClassDef")]
    codeflash_output = function_kind(node, parents); result = codeflash_output # 2.62μs -> 1.37μs

# 3. Large Scale Test Cases

def test_many_functions_module_level():
    # Test 1000 module-level functions
    for i in range(1000):
        node = make_funcdef(f"func_{i}")
        parents = []
        codeflash_output = function_kind(node, parents); result = codeflash_output # 220ns -> 220ns

def test_many_class_methods():
    # Test 500 class methods and 500 static methods in a class
    for i in range(500):
        node = make_funcdef(f"cmethod_{i}", decorators=[make_decorator("classmethod")])
        parents = [FunctionParent(type="ClassDef")]
        codeflash_output = function_kind(node, parents); result = codeflash_output # 651ns -> 441ns
    for i in range(500):
        node = make_funcdef(f"smethod_{i}", decorators=[make_decorator("staticmethod")])
        parents = [FunctionParent(type="ClassDef")]
        codeflash_output = function_kind(node, parents); result = codeflash_output # 651ns -> 441ns

def test_large_mixed_function_types():
    # Mix of module, class, static, classmethod, and instance methods
    for i in range(200):
        # Module-level
        node = make_funcdef(f"func_{i}")
        parents = []
        codeflash_output = function_kind(node, parents) # 240ns -> 240ns

        # Instance method
        node = make_funcdef(f"imethod_{i}")
        parents = [FunctionParent(type="ClassDef")]
        codeflash_output = function_kind(node, parents) # 240ns -> 240ns

        # Static method
        node = make_funcdef(f"smethod_{i}", decorators=[make_decorator("staticmethod")])
        parents = [FunctionParent(type="ClassDef")]
        codeflash_output = function_kind(node, parents) # 240ns -> 240ns

        # Class method
        node = make_funcdef(f"cmethod_{i}", decorators=[make_decorator("classmethod")])
        parents = [FunctionParent(type="ClassDef")]
        codeflash_output = function_kind(node, parents) # 240ns -> 240ns

def test_large_number_of_parents():
    # Deeply nested parents, but top is ClassDef
    node = make_funcdef("foo")
    parents = [FunctionParent(type="ClassDef")] + [FunctionParent(type="Module")] * 999
    codeflash_output = function_kind(node, parents); result = codeflash_output # 17.4μs -> 1.22μs

def test_large_number_of_nested_functions():
    # Deeply nested function (1000 levels)
    node = make_funcdef("foo")
    parents = [FunctionParent(type="FunctionDef")] * 1000
    codeflash_output = function_kind(node, parents); result = codeflash_output # 841ns -> 871ns
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-pr309-2025-06-16T21.29.52 and push.

Codeflash

…extension`)

Here's an optimized version of your program.  
Main changes.
- Replace slices and length-based for-loops with more direct, idiomatic Python control flow (they did nothing).
- Combine checks for better early returns.
- Reduce unnecessary list accesses.
- Process decorator list without unnecessary nesting.
- No changes to function signatures or output.  
All your in-code comments are preserved (there were none).



**Key improvements:**
- Direct mapping of `parents[0].type`; no useless range-loop.
- Early exit for empty `parents`.
- Avoid redundant list traversal.
- Set literal for type checking.

This function has the same return signature and logic, but runs faster and is easier to reason about.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Jun 16, 2025
@KRRT7 KRRT7 closed this Jun 18, 2025
@codeflash-ai codeflash-ai bot deleted the codeflash/optimize-pr309-2025-06-16T21.29.52 branch June 18, 2025 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants